AE_FORCEINLINE AEFLOAT32 AE_CALL AEMath::InvSqrtF32Approx12Bit( const AEFLOAT32 fValue )
{
	const float xhalf = 0.5f * fValue;
	int i = *(int*)&fValue;
	// All positive denormals are less than 0x800000; subtracting that causes underflow
	// into the sign bit. The extra subtracted 0x80000000 then flips that sign bit (1
	// for normal, 0 for denormal). Arithmetic bitshift copies the sign bit into all
	// bits. The resultant mask is 0 for denormals and +0, and ~0 for normals and -0.
	int mask = (i - (signed int)0x80800000) >> 31;

	i = 0x5f375a86 - (i>>1); // Lomonts initial guess
	i &= mask;
	float r = *(float*)&i;

	// Newton steps to improve
	r = (1.5f * r) - (xhalf * r) * (r * r);
	r = (1.5f * r) - (xhalf * r) * (r * r);
	return r;
}

AE_FORCEINLINE AEFLOAT32 AE_CALL AEMath::InvSqrtF32Approx23Bit( const AEFLOAT32 fValue )
{
	const float xhalf = 0.5f * fValue;
	int i = *(int*)&fValue;
	// See comment in InvSqrtF32Approx12Bit.
	int mask = (i - (signed int)0x80800000) >> 31;

	i = 0x5f375a86 - (i>>1); // Lomonts initial guess
	i &= mask;
	float r = *(float*)&i;

	// Newton steps to improve
	r = (1.5f * r) - (xhalf * r) * (r * r);
	r = (1.5f * r) - (xhalf * r) * (r * r);
	r = (1.5f * r) - (xhalf * r) * (r * r);
	return r;
}

AE_FORCEINLINE AEFLOAT32 AE_CALL AEMath::RcpF32Approx12Bit( const AEFLOAT32 fValue )
{
	int i = (2 * 0x3F800000) - *(int *)&fValue; // float 1.0 bits
	// See comment in invSqrtF32Approx12Bit. The XOR corrects for negative x.
	int mask = ((*(int *)&fValue - (signed int)0x80800000) ^ *(int *)&fValue ) >> 31;
	i &= mask;
	float r = *(float *)&i;

	// Newton steps to improve
	r = r * (2.0f - fValue * r);
	r = r * (2.0f - fValue * r);
	return r;
}

AE_FORCEINLINE AEFLOAT32 AE_CALL AEMath::RcpF32Approx23Bit( const AEFLOAT32 fValue )
{
	int i = (2 * 0x3F800000) - *(int *)&fValue; // float 1.0 bits
	// See comment in InvSqrtF32Approx12Bit. The XOR corrects for negative fValue.
	int mask = ((*(int *)&fValue - (signed int)0x80800000) ^ *(int *)&fValue) >> 31;
	i &= mask;
	float r = *(float *)&i;

	// Newton steps to improve
	r = r * (2.0f - fValue * r);
	r = r * (2.0f - fValue * r);
	r = r * (2.0f - fValue * r);
	return r;
}

#ifndef AEMATH_FLOATTOINT_FUNCS
#define AEMATH_FLOATTOINT_FUNCS

AE_FORCEINLINE AEINT32 AE_CALL AEMath::Float2Int( const AEFLOAT32 fValue )
{
	union float_bits
	{
		AEFLOAT32 f;
		AEUINT32 u;
	};

	float_bits fb;
	fb.f = fValue;

	// Convert float to signed int, with AltiVec style overflow
	// (i.e. large float -> 0x7fffffff instead of 0x80000000)

	int e = ((fb.u & 0x7F800000) >> 23) - 127;
	if (e < 0) // clip fractional numbers
		return 0;
	int r = (fb.u & 0x007FFFFF) | 0x00800000;
	int sign = (fb.u & 0x80000000) ? -1 : 1;
	if (e > 23) // adjust with round to zero
		r <<= (e - 23);
	else
		r >>= (23 - e);
	return ((sign * r) & 0x7FFFFFFF) | (fb.u & 0x80000000); // compute dual and set sign bit
}
AE_FORCEINLINE AEINT32 AE_CALL AEMath::Float2Int( const AEDOUBLE64 dValue )
{
	return Float2Int( AEFLOAT32( dValue ) );
}

#endif // AEMATH_FLOATTOINT_FUNCS

#define HK_MATH_min2
template <typename T1,typename T2>
AE_FORCEINLINE  T1 AE_CALL min2( T1 x, T2 y)
{
	return x < (T1)y ? x : (T1)y;
}

#if defined(HK_ARCH_IA32) && ( defined(HK_COMPILER_MSVC) || defined(HK_COMPILER_INTEL) )
template <>
AE_FORCEINLINE  AEFLOAT32 AE_CALL min2<AEFLOAT32, AEFLOAT32>( AEFLOAT32 x, AEFLOAT32 y)
{
	AEFLOAT32 r;
	__asm {
		fld			x
		fld         y
		fucomi		st(0), st(1)
		fcmovnb		st(0), st(1)
		fstp		r
		fstp		st(0)
	}
	return r;
}
template <>
AE_FORCEINLINE  AEDOUBLE64 AE_CALL min2<AEDOUBLE64, AEDOUBLE64>( AEDOUBLE64 x, AEDOUBLE64 y)
{
	AEDOUBLE64 r;
	__asm {
		fld			x
		fld         y
		fucomi		st(0), st(1)
		fcmovnb		st(0), st(1)
		fstp		r
		fstp		st(0)
	}
	return r;
}
#endif

#define HK_MATH_max2
template <typename T1, typename T2>
AE_FORCEINLINE  T1 AE_CALL max2( T1 x, T2 y)
{
	return x > (T1)y ? x : (T1)y;
}

#if defined(HK_ARCH_IA32) && ( defined(HK_COMPILER_MSVC) || defined(HK_COMPILER_INTEL) )
template <>
AE_FORCEINLINE  AEFLOAT32 AE_CALL max2<AEFLOAT32, AEFLOAT32>( AEFLOAT32 x, AEFLOAT32 y)
{
	AEFLOAT32 r;
	__asm {
		fld			x
		fld         y
		fucomi		st(0), st(1)
		fcmovb		st(0), st(1)
		fstp		r
		fstp		st(0)
	}
	return r;
}
template <>
AE_FORCEINLINE  AEDOUBLE64 AE_CALL max2<AEDOUBLE64, AEDOUBLE64>( AEDOUBLE64 x, AEDOUBLE64 y)
{
	AEDOUBLE64 r;
	__asm {
		fld			x
		fld         y
		fucomi		st(0), st(1)
		fcmovb		st(0), st(1)
		fstp		r
		fstp		st(0)
	}
	return r;
}
#endif //  defined(HK_ARCH_IA32) && ( defined(HK_COMPILER_MSVC) || defined(HK_COMPILER_INTEL) )


#if defined(AE_ARCH_IA32) && ( defined(AE_COMPILER_MSVC) || defined(AE_COMPILER_INTEL) ) && !defined(__GCCXML__)

#ifndef AEMATH_CLAMPFUNCS
#define AEMATH_CLAMPFUNCS
template <>
AE_FORCEINLINE AEFLOAT32 AE_CALL AEMath::Clamp<AEFLOAT32, AEFLOAT32, AEFLOAT32>( AEFLOAT32 fValue, AEFLOAT32 fMin, AEFLOAT32 fMax )
{
	AEFLOAT32 r;
	__asm {
		fld         fMax
		fld         fMin
		fld			fValue
		fucomi		st(0), st(1)
		fcmovb		st(0), st(1)
		fucomi		st(0), st(2)
		fcmovnb		st(0), st(2)
		fstp		r
		fstp		st(0)
		fstp		st(0)
	}
	return r;
}
template <>
AE_FORCEINLINE AEDOUBLE64 AE_CALL AEMath::Clamp<AEDOUBLE64, AEDOUBLE64, AEDOUBLE64>( AEDOUBLE64 dValue, AEDOUBLE64 dMin, AEDOUBLE64 dMax )
{
	AEDOUBLE64 r;
	__asm {
		fld         dMax
		fld         dMin
		fld			dValue
		fucomi		st(0), st(1)
		fcmovb		st(0), st(1)
		fucomi		st(0), st(2)
		fcmovnb		st(0), st(2)
		fstp		r
		fstp		st(0)
		fstp		st(0)
	}
	return r;
}
#endif // AEMATH_CLAMPFUNCS

#ifndef AEMATH_FINITEFUNCS
#define AEMATH_FINITEFUNCS

AE_FORCEINLINE AEBOOL32 AE_CALL AEMath::IsFiniteNumber( const AEFLOAT32 fValue )
{
	AEUINT16 statusreg;
	__asm {
		fld			fValue
		fxam
		fstsw		statusreg
		fstp		st(0)
		fwait
	}
	statusreg &= 0x4500;
	return (statusreg & 0x4400) == statusreg; // accept normal finite numbers and zero
}

AE_FORCEINLINE AEBOOL32 AE_CALL AEMath::IsFiniteNumber( const AEDOUBLE64 dValue )
{
	AEUINT16 statusreg;
	__asm {
		fld			dValue
		fxam
		fstsw		statusreg
		fstp		st(0)
		fwait
	}
	statusreg &= 0x4500;
	return (statusreg & 0x4400) == statusreg; // accept normal finite numbers and zero
}
#endif // AEMATH_FINITEFUNCS
#endif // defined(AE_ARCH_IA32) && ( defined(AE_COMPILER_MSVC) || defined(AE_COMPILER_INTEL) )
